package com.leyou.order.service;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.leyou.common.auth.pojo.UserHolder;
import com.leyou.common.constants.LyConstants;
import com.leyou.common.constants.MQConstants;
import com.leyou.common.exception.pojo.ExceptionEnum;
import com.leyou.common.exception.pojo.LyException;
import com.leyou.common.pojo.PageResult;
import com.leyou.common.utils.BeanHelper;
import com.leyou.common.utils.JsonUtils;
import com.leyou.item.client.ItemClient;
import com.leyou.item.entity.Sku;
import com.leyou.order.dto.CartDTO;
import com.leyou.order.dto.OrderDTO;
import com.leyou.order.dto.OrderStatusEnum;
import com.leyou.order.dto.OrderVO;
import com.leyou.order.entity.Order;
import com.leyou.order.entity.OrderDetail;
import com.leyou.order.entity.OrderLogistics;
import com.leyou.order.mapper.OrderDetailMapper;
import com.leyou.order.mapper.OrderLogisticsMapper;
import com.leyou.order.mapper.OrderMapper;
import com.leyou.order.utils.PayHelper;
import com.leyou.user.client.UserClient;
import com.leyou.user.dto.AddressDTO;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
@Transactional
public class OrderService extends ServiceImpl<OrderDetailMapper, OrderDetail> {

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private OrderDetailMapper orderDetailMapper;

    @Autowired
    private OrderLogisticsMapper orderLogisticsMapper;

    @Autowired
    private ItemClient itemClient;

    @Autowired
    private UserClient userClient;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private PayHelper payHelper;

    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private AmqpTemplate amqpTemplate;
    /**
     * 超时支付延时时间 还库存
     */
    @Value("${spring.rabbitmq.timeout.repayStockTime}")
    private Integer repayStockTime;

    @Value("${spring.rabbitmq.timeout.changeOrderState}")
    private Integer changeOrderState;

    @GlobalTransactional
    public Long saveOrder(OrderDTO orderDTO) {
        //保存订单
        //创建订单对象
        Order order = new Order();
        order.setUserId(UserHolder.getUserId());
        order.setStatus(OrderStatusEnum.INIT.value());
        order.setSourceType(2);
        order.setInvoiceType(0);
        order.setPaymentType(orderDTO.getPaymentType());
        order.setPostFee(0L);
        order.setActualFee(1L);
        //获取购买的购物车信息
        List<CartDTO> carts = orderDTO.getCarts();
        //将购买的列表结构的购物车数据改成map结构
        Map<Long, Integer> cartMap = carts.stream().collect(Collectors.toMap(CartDTO::getSkuId, CartDTO::getNum));
        //获取到购买的sku的id的集合
        List<Long> skuIds = carts.stream().map(CartDTO::getSkuId).collect(Collectors.toList());
        //根据sku的id的集合查询sku对象的集合
        List<Sku> skus = itemClient.findSkusByIds(skuIds);
        //计算总金额  每个sku的价格【sku对象中】*购买的数量【参数中】
        Long totalFee = skus.stream().mapToLong(sku -> sku.getPrice() * cartMap.get(sku.getId())).sum();
        order.setTotalFee(totalFee);
        //订单数据入库
        orderMapper.insert(order);

        //获取订单id
        Long orderId = order.getOrderId();

        //保存订单详情
        List<OrderDetail> orderDetails = new ArrayList<>();
        skus.forEach(sku -> {
            OrderDetail orderDetail = new OrderDetail();
            orderDetail.setOrderId(orderId);
            orderDetail.setNum(cartMap.get(sku.getId()));
            orderDetail.setImage(StringUtils.substringBefore(sku.getImages(), ","));
            orderDetail.setOwnSpec(sku.getOwnSpec());
            orderDetail.setPrice(sku.getPrice());
            orderDetail.setTitle(sku.getTitle());
            orderDetail.setSkuId(sku.getId());
            orderDetails.add(orderDetail);
        });
        //批量添加订单详情
        saveBatch(orderDetails);

        //保存物流信息
        //得到物流信息dto
        AddressDTO addressDTO = userClient.queryAddressById(UserHolder.getUserId(), orderDTO.getAddressId());
        //将dto对象转成entity
        OrderLogistics orderLogistics = BeanHelper.copyProperties(addressDTO, OrderLogistics.class);
        //给物流对象赋订单id
        orderLogistics.setOrderId(orderId);
        //入库
        orderLogisticsMapper.insert(orderLogistics);
        //减库存
        itemClient.minusStock(cartMap);

        //发送订单到消息队列(延时,用于还库存)
        this.rabbitTemplate.convertAndSend(
                MQConstants.Exchange.REPAY_STOCK_EXCHANGE,
                MQConstants.RoutingKey.REPAY_STOCK_KEY,
                order.getOrderId(),
                message -> {
                    // 注意这里时间可以使long，而且是设置header
                    message.getMessageProperties().setDelay(repayStockTime);
                    return message;
                });

        //发送订单到消息队列(延时,用于还将订单状态改为失效)
        this.rabbitTemplate.convertAndSend(
                MQConstants.Exchange.CHANGE_ORDER_STATE_EXCHANGE,
                MQConstants.RoutingKey.CHANGE_ORDER_STATE_KRY,
                order.getOrderId(),
                message -> {
                    // 注意这里时间可以使long，而且是设置header
                    message.getMessageProperties().setDelay(changeOrderState);
                    return message;
                });
        //删除订单缓存
        delPageOrder(orderId);
        //通知购物车
        //发用户信息给购物车
        amqpTemplate.convertAndSend(MQConstants.Exchange.CART_EXCHANGE_NAME,
                MQConstants.RoutingKey.cart_UP_KEY, order.getUserId());
        return orderId;
    }
    //生成二维码
    public String getPayUrl(Long id) {
        //得到当前支付链接在redis中的key值
        String key = LyConstants.PAY_URL_PRE + id;
        //从redis中获取支付链接
        String payUrl = redisTemplate.opsForValue().get(key);
        //判空
        if (StringUtils.isNotBlank(payUrl)) {
            return payUrl;
        }
        //根据id获取订单对象
        Order order = orderMapper.selectById(id);

        //判空
        if (order == null) {
            throw new LyException(ExceptionEnum.ORDER_NOT_FOUND);
        }
        //判断订单状态
        if (!order.getStatus().equals(OrderStatusEnum.INIT.value()) &&
                !order.getStatus().equals(OrderStatusEnum.NOSTOCK.value()) &&
                !order.getStatus().equals(OrderStatusEnum.FAILURE.value())) {
            if (!order.getStatus().equals(OrderStatusEnum.INIT.value())) {
                throw new LyException(501, "订单已支付");
            } else if (order.getStatus().equals(OrderStatusEnum.FAILURE.value())) {
                throw new LyException(501, "订单已失效");
            } else if (!order.getStatus().equals(OrderStatusEnum.NOSTOCK.value())) {
                //查库存是否还有
                OrderDetail orderDetailEntity = new OrderDetail();
                orderDetailEntity.setOrderId(order.getOrderId());
                QueryWrapper<OrderDetail> query = Wrappers.query(orderDetailEntity);
                List<OrderDetail> orderDetails = orderDetailMapper.selectList(query);
                Map<Long, Integer> map = new HashMap<>();
                orderDetails.forEach(orderDetail -> {
                    map.put(orderDetail.getSkuId(), orderDetail.getNum());
                });
                itemClient.queryStock(map);  //没有库存直接报错
            }
        }
        //调用支付工具类
        payUrl = payHelper.getPayUrl(id, order.getActualFee());
        //将支付链接加入redis
        redisTemplate.opsForValue().set(key, payUrl, 2, TimeUnit.HOURS);
        return payUrl;
    }
    public OrderVO fondOrderVOByOrderId(Long id) {
        //查询订单
        Order order = orderMapper.selectById(id);
        if (order == null) {
            throw new LyException(ExceptionEnum.ORDER_NOT_FOUND);
        }
        OrderVO orderVO = BeanHelper.copyProperties(order, OrderVO.class);
        //查询订单详情
        OrderDetail entity = new OrderDetail();
        entity.setOrderId(id);
        Wrapper<OrderDetail> wrapper = Wrappers.query(entity);
        List<OrderDetail> orderDetails = orderDetailMapper.selectList(wrapper);
        orderVO.setDetailList(orderDetails);
        //查询物流信息
        OrderLogistics orderLogistics = orderLogisticsMapper.selectById(id);
        orderVO.setLogistics(orderLogistics);
        return orderVO;
    }

    public Integer findStatus (Long id){
        Order order = orderMapper.selectById(id);
        if (order == null) {
            throw new LyException(ExceptionEnum.ORDER_NOT_FOUND);
        }
        return order.getStatus();
    }
    //删除订单缓存页
    public  void delPageOrder (Long orderId){
        //查询缓存中数据
        String key = UserHolder.getUserId() + LyConstants.ORDER_KEY;
        redisTemplate.delete(key);
    }
    public Map<String, String> wxNotify (Map < String, String > paramMap){
        //对通信标识和交易标识进行校验
        payHelper.checkResp(paramMap);
        //从微信的通知参数中获取商户订单号
        String outTradeNo = paramMap.get("out_trade_no");
        Long orderId = Long.valueOf(outTradeNo);
        //从微信的通知参数中获取支付金额
        String totalFee = paramMap.get("total_fee");
        Long actualFee = Long.valueOf(totalFee);
        //通过订单号查询订单
        Order order = orderMapper.selectById(orderId);
        if (order == null) {
            log.error("【微信支付回调通知】异常，订单不存在！");
            throw new LyException(ExceptionEnum.ORDER_NOT_FOUND);
        }
        //判断本地数据库中对应的订单是否已经支付
        if (!order.getStatus().equals(OrderStatusEnum.INIT.value())) {
            log.error("【微信支付回调通知】异常，订单已支付！");
            throw new LyException(501, "订单已支付！");
        }
        //比对金额是否一致
        if (!actualFee.equals(order.getActualFee())) {
            log.error("【微信支付回调通知】异常，订单金额不一致！");
            throw new LyException(501, "订单金额不一致！");
        }
        //修改订单状态
        Order entity = new Order();
        entity.setOrderId(orderId);
        entity.setStatus(OrderStatusEnum.PAY_UP.value());
        int count = orderMapper.updateById(entity);
        if (count != 1) {
            //省略了日志入库
            log.error("【微信支付回调通知】异常，订单状态更新失败！");
        }
        //删除订单缓存
        delPageOrder(orderId);
        Map<String, String> result = new HashMap<>();
        result.put("return_code", "SUCCESS");
        result.put("return_msg", "OK");
        return result;
    }
    public PageResult<OrderVO> findOrderByPage (Integer status, Long page, Long rows){
        String key = UserHolder.getUserId() + LyConstants.ORDER_KEY;
        //redisTemplate.delete(key);
        //从缓存中获取数据
        BoundHashOperations<String, String, String> orderMap = redisTemplate.boundHashOps(key);
        //获取分页的缓存数据
        String pageKey = status + page.toString();
        if (orderMap.hasKey(pageKey)) {
            String orderVos = orderMap.get(pageKey);
            PageResult pageResult = JsonUtils.toBean(orderVos, PageResult.class);
            return pageResult;
        }
        //封装分页对象
        IPage<Order> iPage = new Page<>(page, rows, true);
        //获取条件对象
        QueryWrapper<Order> wrapper = Wrappers.query();
        //设置条件
        if (status != null) {
            wrapper.eq("status", status);
        }
        //分页查询
        iPage = orderMapper.selectPage(iPage, wrapper);
        List<Order> orders = iPage.getRecords();
        if (CollectionUtils.isEmpty(orders)) {
            throw new LyException(ExceptionEnum.INVALID_ORDER_STATUS);
        }
        //封装订单数据
        List<OrderVO> orderVOS = BeanHelper.copyWithCollection(orders, OrderVO.class);
        //查询订单详情商品
        OrderDetail entity = new OrderDetail();
        orderVOS.forEach(orderVO -> {
            Long id = orderVO.getOrderId();
            //查询订单详情
            entity.setOrderId(id);
            Wrapper<OrderDetail> detailWrapper = Wrappers.query(entity);
            List<OrderDetail> orderDetails = orderDetailMapper.selectList(detailWrapper);
            orderVO.setDetailList(orderDetails);
            //查询物流信息
            OrderLogistics orderLogistics = orderLogisticsMapper.selectById(id);
            orderVO.setLogistics(orderLogistics);
        });

        //创建一个自定义的分页对象
        PageResult<OrderVO> pageResult = new PageResult<>(
                iPage.getTotal(),
                iPage.getPages(),
                orderVOS
        );
        orderMap.put(pageKey, JsonUtils.toString(pageResult));
        return pageResult;
    }
}
